#include <climits>
#include <cmath>
#include <iostream>
#include <memory>

void f(const int &x) { const_cast<int &>(x) = 0; }

struct A {
  int x, y;
};

struct B {
  virtual void f() { std::cout << __func__ << "\n"; }
  virtual ~B() = default;
};

struct C : public B {
  C(int *x) : x_{x} {}
  int *g() { return x_; }
  int *x_;
};

struct X {
  virtual void f() { std::cout << __func__ << "\n"; }
};

struct Y : public X {
  void f() override { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

int main(int argc, char *argv[]) {
  // C Style Casting
  double x = M_PI;
  int xx = (int)x;
  std::cout << xx << "\n";
  long z = LONG_MAX;
  int zz = (int)z; // dangerous. overflow.
  std::cout << zz << "\n";

  // Const Casting
  int y = 123;
  f(y);
  std::cout << y << "\n";

  // Reinterpret Casting

  A a{1, 2};
  char *buf = reinterpret_cast<char *>(&a);
  for (int i = 0; i < sizeof(A); ++i) {
    std::cout << static_cast<int>(buf[i]) << " ";
  } // output 10002000

  // Static Casting

  auto b = std::make_unique<B>();

  // downcasting may be dangerous
  auto c = static_cast<C *>(b.get()); // dangerous.
  auto w = c->g();
  // std::cout << *w << "\n"; // segment fault

  // Dynamic Casting
  auto x1 = std::make_unique<X>();
  auto y1 = std::make_unique<Y>();

  // downcast
  auto y11 = dynamic_cast<Y *>(x1.get());
  std::cout << "Is dynamic_cast(*x) to *y success? " << !!y11 << "\n";
  auto x11 = dynamic_cast<X *>(y1.get());
  std::cout << "Is dynamic_cast(*y) to *x success? " << !!x11 << "\n";
  return 0;
}
